﻿using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;

namespace HashFoo.Rest.Server
{
    /// <summary>
    /// A module that supresses the asp.net forms authentication module redirect to a "login page"
    /// when the application throws an unauthorized/401.
    /// </summary>
    /// <remarks>
    /// "Borrowed" from Phil Haack: http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx
    /// </remarks>
    public class SuppressFormsAuthenticationRedirectModule : IHttpModule
    {
        static readonly object SuppressAuthenticationKey = new Object();

        /// <summary>
        /// Supresses authentication redirect by setting the supression key in the http context.
        /// </summary>
        /// <param name="context"></param>
        public static void SuppressAuthenticationRedirect(HttpContext context)
        {
            SuppressAuthenticationRedirect(new HttpContextWrapper(context));
        }

        /// <summary>
        /// Supresses authentication redirect by setting the supression key in the http context.
        /// </summary>
        /// <param name="context"></param>
        public static void SuppressAuthenticationRedirect(HttpContextBase context)
        {
            context.Items[SuppressAuthenticationKey] = true;
        }

        /// <summary>
        /// Initializes the module for the current application context.
        /// </summary>
        /// <param name="context"></param>
        public void Init(HttpApplication context)
        {
            context.PostReleaseRequestState += OnPostReleaseRequestState;
            context.EndRequest += OnEndRequest;
        }

        static void OnPostReleaseRequestState(object source, EventArgs args)
        {
            var context = (HttpApplication) source;
            var response = context.Response;
            var request = context.Request;

            if (response.StatusCode == 401 && request.Headers["X-Requested-With"] ==
                "XMLHttpRequest")
            {
                SuppressAuthenticationRedirect(context.Context);
            }
        }

        static void OnEndRequest(object source, EventArgs args)
        {
            var context = (HttpApplication) source;
            var response = context.Response;

            if (!context.Context.Items.Contains(SuppressAuthenticationKey)) return;

            response.TrySkipIisCustomErrors = true;
            response.ClearContent();
            response.StatusCode = 401;
            response.RedirectLocation = null;
        }

        public void Dispose()
        {
        }

        /// <summary>
        /// Register the suppressor as a http module.
        /// </summary>
        public static void Register()
        {
            DynamicModuleUtility.RegisterModule(
                typeof (SuppressFormsAuthenticationRedirectModule));
        }
    }
}